<template>
	<div class="preview-file">
		<div class="preview-main" ref="previewMainRef">
			<div class="preview-tools">
				<span
					class="prev"
					:class="{
						disabled: page === 1,
					}"
					title="上一页"
					@click="onPrevPage"
				>
					<el-icon><ArrowUp /></el-icon>
				</span>
				<span
					class="next"
					:class="{
						disabled: page === total,
					}"
					title="下一页"
					@click="onNextPage"
				>
					<el-icon><ArrowDown /></el-icon>
				</span>
				<input type="number" class="input" min="1" :max="total" v-model="page" @input="onPageChange" />
				<span class="divider"></span>
				<span class="total">{{ total }}</span>
				<span class="fullscreen" title="全屏显示" @click="onToggleFullScreen">
					<el-icon><FullScreen /></el-icon>
				</span>
				<span
					class="prev"
					:class="{
						disabled: current === 0,
					}"
					title="上一篇"
					@click="onPrevCurrent"
				>
					<el-icon><DArrowLeft /></el-icon>
				</span>
				<span
					class="next"
					:class="{
						disabled: current === fileList.length - 1,
					}"
					title="下一篇"
					@click="onNextCurrent"
				>
					<el-icon><DArrowRight /></el-icon>
				</span>
			</div>
			<div
				class="preview-content"
				:class="{
					isPPT,
					isDefault: !isPPT,
				}"
				@scroll="onPreviewContentScroll"
				ref="previewContentRef"
			>
				<div v-if="isPPT" key="ppt">
					<img :src="nowPPt" :alt="file.name" />

					<div
						class="prev arrow"
						:class="{
							disabled: page === 1,
						}"
						@click="onPrevPage"
					></div>
					<div
						class="next arrow"
						:class="{
							disabled: page === total,
						}"
						@click="onNextPage"
					></div>
				</div>
				<div v-else key="default">
					<img :src="item" v-for="(item, index) in list" :key="index" :alt="file.name" />
				</div>
			</div>
		</div>
	</div>
</template>

<script setup>
const props = defineProps({
	fileList: {
		type: Array,
		required: true,
	},
	modelValue: {
		type: Number,
		default: 0,
	},
})
const emits = defineEmits(["update:modelValue"])

const current = computed({
	get() {
		return props.modelValue
	},
	set(val) {
		emits("update:modelValue", val)
	},
})
const page = ref(1)

const fileStore = {}

const file = computed(() => props.fileList[current.value] || { fileName: "" })
const extName = computed(() => {
	if (file.value) {
		return file.value.fileName.split(".").pop()
	}
	return ""
})
const isPPT = computed(() => extName.value === "ppt" || extName.value === "pptx")
const nowPPt = computed(() => {
	if (isPPT.value) {
		return list.value[page.value - 1]
	}
	return ""
})

const list = ref([])
const total = computed(() => list.value.length)

const previewMainRef = ref()
const previewContentRef = ref()
let previewContentImg = []
const IMG_MARGIN = "15px"

async function getFileMessage() {
	if (!file.value.url) {
		return
	}

	page.value = 1
	if (fileStore[file.value.id]) {
		list.value = fileStore[file.value.id]

		await nextTick()
		if (previewContentRef.value) {
			previewContentImg = previewContentRef.value.querySelectorAll("img")
		}
		return
	}

	list.value = file.value.url
	fileStore[file.value.id] = list.value

	await nextTick()
	if (previewContentRef.value) {
		previewContentImg = previewContentRef.value.querySelectorAll("img")
	}
}
function onPageChange() {
	if (page.value < 1) {
		page.value = 1
	} else if (page.value > total.value) {
		page.value = total.value
	}

	if (!isPPT.value) {
		previewContentRef.value.scrollTo({
			top: calcImgHeight(),
			left: 0,
			behavior: "smooth",
		})
	}
}
function onPrevPage() {
	if (page.value <= 1) {
		return
	}
	page.value--

	if (!isPPT.value) {
		previewContentRef.value.scrollTo({
			top: calcImgHeight(),
			left: 0,
			behavior: "smooth",
		})
	}
}
function onNextPage() {
	if (page.value >= total.value) {
		return
	}
	page.value++
	if (!isPPT.value) {
		previewContentRef.value.scrollTo({
			top: calcImgHeight(),
			left: 0,
			behavior: "smooth",
		})
	}
}
async function onPrevCurrent() {
	if (current.value > 0) {
		current.value--
		await nextTick()
		getFileMessage()
	}
}
async function onNextCurrent() {
	if (current.value < props.fileList.length - 1) {
		current.value++
		await nextTick()
		getFileMessage()
	}
}
function onToggleFullScreen() {
	const previewContent = previewMainRef.value
	if (!previewContent) return

	if (document.fullscreenElement) {
		document.exitFullscreen()
	} else {
		if (previewContent.requestFullscreen) {
			previewContent.requestFullscreen()
		} else if (previewContent.webkitRequestFullscreen) {
			previewContent.webkitRequestFullscreen()
		} else if (previewContent.mozRequestFullScreen) {
			previewContent.mozRequestFullScreen()
		} else if (previewContent.msRequestFullscreen) {
			previewContent.msRequestFullscreen()
		}
	}
}
function onPreviewContentScroll() {
	const { scrollTop } = previewContentRef.value

	let index = -1
	for (let i = 0; i < previewContentImg.length; i++) {
		const element = previewContentImg[i]
		if (scrollTop >= element.offsetTop - parseInt(IMG_MARGIN)) {
			index = i
		}
	}

	if (index > -1) {
		page.value = index + 1
	}
}
function calcImgHeight() {
	let height = [...previewContentImg].reduce((prev, cur, index) => {
		if (index >= page.value - 1) return prev
		return prev + cur.getBoundingClientRect().height + parseInt(IMG_MARGIN)
	}, 1)
	return height
}

watch(() => props.fileList, getFileMessage, { immediate: true })
</script>

<style lang="scss" scoped>
.preview-file {
	background: #f5f6fa;
	.preview-title {
		font-size: 16px;
		padding: 7px 15px;
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
		color: #333;
	}
	.preview-main {
		background: #3d3d3d;
		user-select: none;
		.preview-tools {
			$height: 25px;
			$current-bg: #606060;
			$radius: 3px;

			display: flex;
			justify-content: flex-start;
			align-items: center;
			padding: 5px 15px;
			box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
			background: #4a4a4a;
			gap: 10px;
			color: #fff;

			.prev,
			.next {
				font-size: 18px;
				width: 30px;
				height: $height;
				display: flex;
				justify-content: center;
				align-items: center;
				cursor: pointer;
				border-radius: $radius;
				transition: all 0.1s ease;
				&:not(.disabled) {
					&:hover {
						box-shadow: inset 0 0 7px rgba(0, 0, 0, 0.8);
						background: $current-bg;
					}
				}
				&.disabled {
					cursor: not-allowed;
					opacity: 0.3;
				}
			}
			.input {
				width: 75px;
				height: $height;
				border-radius: $radius;
				background: $current-bg;
				text-indent: 7px;
				margin-left: 25px;
				color: inherit;
			}
			.divider {
				height: 12px;
				background: #fff;
				width: 1px;
				transform: skew(-13deg);
			}
			.fullscreen {
				margin-left: auto;
				font-size: 16px;
				display: flex;
				justify-content: center;
				align-items: center;
				cursor: pointer;
				border-radius: $radius;
				transition: all 0.1s ease;
				width: $height;
				height: $height;
				&:hover {
					box-shadow: inset 0 0 7px rgba(0, 0, 0, 0.8);
					background: $current-bg;
				}
			}
		}
	}
	.preview-content {
		position: relative;
		padding: 15px;
		user-select: none;
		&.isPPT {
		}
		&.isDefault {
			max-height: 650px;
			overflow-y: auto;
			img {
				margin-bottom: v-bind(IMG_MARGIN);
			}
		}
		.arrow {
			position: absolute;
			top: 0;
			bottom: 0;
			margin: auto;
			background: rgba(#fff, 0.3);
			display: flex;
			justify-content: center;
			align-items: center;
			z-index: 5;
			height: 145px;
			width: 45px;
			cursor: pointer;
			transition: all 0.1s ease;
			&.prev {
				left: 0;
				&::before {
					transform: rotate(45deg);
				}
			}
			&.next {
				right: 0;
				&::before {
					transform: rotate(-135deg);
				}
			}
			&::before {
				content: "";
				width: 16px;
				height: 16px;
				border-bottom: 5px solid #fff;
				border-left: 5px solid #fff;
			}
			&.disabled {
				cursor: not-allowed;
				opacity: 0.3;
			}
			&:not(.disabled) {
				&:hover {
					background: rgba(#fff, 0.5);
				}
			}
		}
		img {
			display: block;
			width: 100%;
			user-select: none;
		}
	}
}
</style>
